package br.com.ime.usp.cmep;

import java.io.IOException;
import java.io.InputStream;
import java.util.StringTokenizer;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.CheckBox;
import android.widget.Toast;

import com.markupartist.android.widget.ActionBar;
import com.markupartist.android.widget.ActionBar.AbstractAction;

public class MapActivity extends Activity{

	private MapShow ms; //View do mapa
	private Thread t;
	private Handler hThread;
	private Handler mMainHandler;
	private double latitud;
	private double longitud;
	private LocationManager locManager;
	private LocationListener locListener;
	private float oldX; //penultimo valor x que detectou um toque na tela
	private float oldY; //pelultimo valor x que detectou um toque na tela
	private float currentX; //ultimo valor x que detectou um toque na tela
	private float currentY; //ultimo valor y que detectou um toque na tela
	private CheckBox mapa_checkbox;
	private int xDraw; //valor x onde comecar a desenhar na tela
	private int yDraw; //valor y onde comecar a desenhar na tela
	private float proportion; //proporcao para reajustar os tamanhos de acordo com o tamanho da tela
	private int barHeight; //valor em pixels da barra do android
	private int xGPS; //conversao da longitude para os valores do bitmap
	private int yGPS; //conversao da latitude para os valores do bitmap
	private boolean centraliza; //centraliza na posicao do usuario
	private int screenWidth;
	private int screenHeight;
	private boolean startPortrait; //true se o mapa foi aberto em modo paisagem
	private DisplayMetrics metrics; //pegar infos sobre resolucao da tela
	private AssetManager assetManager;
	
	public MapShow getMs() {
		return ms;
	}

	public void setMs(MapShow ms) {
		this.ms = ms;
	}

	public Thread getT() {
		return t;
	}

	public void setT(Thread t) {
		this.t = t;
	}

	public Handler gethThread() {
		return hThread;
	}

	public void sethThread(Handler hThread) {
		this.hThread = hThread;
	}

	public Handler getmMainHandler() {
		return mMainHandler;
	}

	public void setmMainHandler(Handler mMainHandler) {
		this.mMainHandler = mMainHandler;
	}

	public double getLatitud() {
		return latitud;
	}

	public void setLatitud(double latitud) {
		this.latitud = latitud;
	}

	public double getLongitud() {
		return longitud;
	}

	public void setLongitud(double longitud) {
		this.longitud = longitud;
	}

	public LocationManager getLocManager() {
		return locManager;
	}

	public void setLocManager(LocationManager locManager) {
		this.locManager = locManager;
	}

	public LocationListener getLocListener() {
		return locListener;
	}

	public void setLocListener(LocationListener locListener) {
		this.locListener = locListener;
	}

	public float getOldX() {
		return oldX;
	}

	public void setOldX(float oldX) {
		this.oldX = oldX;
	}

	public float getOldY() {
		return oldY;
	}

	public void setOldY(float oldY) {
		this.oldY = oldY;
	}

	public float getCurrentX() {
		return currentX;
	}

	public void setCurrentX(float currentX) {
		this.currentX = currentX;
	}

	public float getCurrentY() {
		return currentY;
	}

	public void setCurrentY(float currentY) {
		this.currentY = currentY;
	}

	public CheckBox getMapa_checkbox() {
		return mapa_checkbox;
	}

	public void setMapa_checkbox(CheckBox mapa_checkbox) {
		this.mapa_checkbox = mapa_checkbox;
	}

	public int getxDraw() {
		return xDraw;
	}

	public void setxDraw(int xDraw) {
		this.xDraw = xDraw;
	}

	public int getyDraw() {
		return yDraw;
	}

	public void setyDraw(int yDraw) {
		this.yDraw = yDraw;
	}

	public float getProportion() {
		return proportion;
	}

	public void setProportion(float proportion) {
		this.proportion = proportion;
	}

	public int getBarHeight() {
		return barHeight;
	}

	public void setBarHeight(int barHeight) {
		this.barHeight = barHeight;
	}

	public int getxGPS() {
		return xGPS;
	}

	public void setxGPS(int xGPS) {
		this.xGPS = xGPS;
	}

	public int getyGPS() {
		return yGPS;
	}

	public void setyGPS(int yGPS) {
		this.yGPS = yGPS;
	}

	public boolean isCentraliza() {
		return centraliza;
	}

	public void setCentraliza(boolean centraliza) {
		this.centraliza = centraliza;
	}

	public int getScreenWidth() {
		return screenWidth;
	}

	public void setScreenWidth(int screenWidth) {
		this.screenWidth = screenWidth;
	}

	public int getScreenHeight() {
		return screenHeight;
	}

	public void setScreenHeight(int screenHeight) {
		this.screenHeight = screenHeight;
	}

	public boolean isStartPortrait() {
		return startPortrait;
	}

	public void setStartPortrait(boolean startPortrait) {
		this.startPortrait = startPortrait;
	}

	public DisplayMetrics getMetrics() {
		return metrics;
	}

	public void setMetrics(DisplayMetrics metrics) {
		this.metrics = metrics;
	}

	public AssetManager getAssetManager() {
		return assetManager;
	}

	public void setAssetManager(AssetManager assetManager) {
		this.assetManager = assetManager;
	}

	public Handler getUpdateHandler() {
		return updateHandler;
	}

	public void setUpdateHandler(Handler updateHandler) {
		this.updateHandler = updateHandler;
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.map);
		
		// action bar
        final ActionBar actionBar = (ActionBar) findViewById(R.id.actionbar);
        actionBar.setTitle(getString(R.string.mapa_titulo));
        actionBar.setHomeAction(new HomeAction(this));        
        actionBar.addAction(new OptionAction(this));
        actionBar.addAction(new BackAction(this));
        
		// configuracao do mapa
		ms = (MapShow) findViewById(R.id.mapShow1);
		mapa_checkbox = (CheckBox) findViewById(R.id.mapa_checkbox);
		
		mapa_checkbox.setOnClickListener(new View.OnClickListener() {
			 
			  public void onClick(View v) {
				if (((CheckBox) v).isChecked()) {
					centraliza = true;
					if(!locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
						Toast.makeText( getApplicationContext(), "Gps desligado", Toast.LENGTH_SHORT ).show();
					}
				}
			  }
			});
		
		metrics = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(metrics);
		int density = metrics.densityDpi;
		screenWidth = metrics.widthPixels;
		screenHeight = metrics.heightPixels;
		if(screenWidth < screenHeight)
			startPortrait = true;
		else
			startPortrait = false;
		if(density == DisplayMetrics.DENSITY_LOW){
			proportion = 1;
			barHeight = 19;
		}
		else if(density == DisplayMetrics.DENSITY_MEDIUM){
			proportion = (float)4/3;
			barHeight = 25;
		}
		else{
			proportion = 2;
			barHeight = 38;
		}
		ms.setProportion(this.proportion);
		ms.setTextHeight(screenHeight - (int)(2.75*barHeight));
		
		assetManager = getAssets();
		readPath();
		
		t = new Thread(new MoveThread());
		t.start();

		locManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
		locListener = new MyLocationListener();
		locManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 5000, 0, locListener);

		mMainHandler = new Handler() {
			public void handleMessage(Message msg) {
				ms.invalidate();
			}
		};
	}

	//menu
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.mapa_menu, menu);
        return true;
    }

    //botoes de menu para exibir/esconder informacoes sobre o mapa
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.mapa_bandejao:     
            	ms.changeBandejao();
            	updateScreen();
                break;
            case R.id.mapa_circular1:
            	ms.changeCircular1();
            	updateScreen();
            	break;
            case R.id.mapa_circular2:
            	ms.changeCircular2();
            	updateScreen();
            	break;
        }
        return true;
    }
	
    public boolean onTouchEvent(MotionEvent me) {
		int action = me.getAction();
		currentX = me.getX();
		currentY = me.getY();
		mapa_checkbox.setChecked(false);
		centraliza = false;

		if (action == MotionEvent.ACTION_MOVE) {
			int difX = (int)(currentX - oldX);
			int difY = (int)(currentY - oldY);
			xDraw = xDraw + difX;
			yDraw = yDraw + difY;
			
			updateScreen();
		}
		
		oldX = currentX;
		oldY = currentY;

		return true;
	}
	
	//recalcula width e height quando ocorre mudanca de orientacao
	public void onConfigurationChanged(Configuration newConfig) {
	    super.onConfigurationChanged(newConfig);
	    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
	        if(startPortrait){
	        	screenWidth = metrics.heightPixels;
	        	screenHeight = metrics.widthPixels;
	        }
	        else{
	        	screenWidth = metrics.widthPixels;
	        	screenHeight = metrics.heightPixels;
	        }
	    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
	    	if(!startPortrait){
	        	screenWidth = metrics.heightPixels;
	        	screenHeight = metrics.widthPixels;
	        }
	        else{
	        	screenWidth = metrics.widthPixels;
	        	screenHeight = metrics.heightPixels;
	        }
	    }
	    ms.setTextHeight(screenHeight - (int)(2.75*barHeight));
	    updateScreen();
	}

	public class MyLocationListener implements LocationListener
	{
		public void onLocationChanged(Location loc)
		{
			latitud = loc.getLatitude();
			longitud = loc.getLongitude();
			yGPS = convertLatitude(latitud);
			xGPS = convertLongitude(longitud);
			ms.setyGPS(yGPS);
			ms.setxGPS(xGPS);
			if(centraliza){
				xDraw = -(xGPS - screenWidth/2);
				yDraw = -(yGPS - screenHeight/2 + barHeight);
			}

			if(centraliza && userOut()){
				Toast.makeText( getApplicationContext(), "Fora da área da USP", Toast.LENGTH_SHORT ).show();
			}
			updateScreen();
		}

		public void onProviderDisabled(String provider)
		{
			Toast.makeText( getApplicationContext(), "Gps desligado", Toast.LENGTH_SHORT ).show();
		}

		public void onProviderEnabled(String provider)
		{
			Toast.makeText( getApplicationContext(), "Gps ligado",	Toast.LENGTH_SHORT).show();
		}

		public void onStatusChanged(String provider, int status, Bundle extras)
		{
		}

	}/* End of Class MyLocationListener */

	@Override
	public void onPause(){
		super.onPause();
		if(!t.isInterrupted()){
			t.interrupt();
		}
		ms.recycleMap();
		ms.setbMap(null);
		locManager.removeUpdates(locListener);
		System.gc();
	}

	@Override
	public void onResume(){
		super.onResume();
		if(t.isInterrupted())
			try{
				t.start();
			}catch (Exception e) {
				;//ignora
			}
		if(ms.getbMap() == null){
			ms.createbMap();
		}
		locManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 5000, 0, locListener);
	}
	
	@Override
	public void onDestroy(){
		super.onDestroy();
		locManager.removeUpdates(locListener);
		locListener = null;
		locManager = null;
		metrics = null;
		mMainHandler = null;
		hThread = null;
		ms = null;
		t = null;
		mapa_checkbox = null;
		System.gc();
	}
	
	public Handler updateHandler = new Handler(){
	};

	public class MoveThread extends Thread {		 
		public void run() {
			Looper.prepare();
			hThread = new Handler(){
				public void handleMessage(Message msg) {
					ms.update(xDraw, yDraw);
					mMainHandler.sendEmptyMessage(0);
					super.handleMessage(msg);
				}
			};
			Looper.loop();
		}
	}
	
		
	//converte um latitude para um valor nas coordenadas do bitmap
	public int convertLatitude(double latitud){
		double res = (latitud + 23.5494)*1000000/(30.80808/proportion);
		return -(int)Math.round(res);
	}
	
	//converte um longitude para um valor nas coordenadas do bitmap
	public int convertLongitude(double longitud){
		double res = (longitud + 46.7443)*1000000/(33.61494/proportion);
		return (int)Math.round(res);
	}
	
	//true se o usuario se encontra fora da area do mapa
	public boolean userOut(){
		if(xGPS  < 0 || yGPS < 0 || xGPS > ms.getbMap().getWidth() || yGPS  > ms.getbMap().getHeight()){
			return true;
		}
		return false;
	}
	
	//atualiza a tela
	public void updateScreen()
	{
		if(xDraw > 0)
			xDraw = 0;
		if(yDraw > 0)
			yDraw = 0;
		
		if(xDraw < - (ms.getbMap().getWidth() - screenWidth))
			xDraw = - (ms.getbMap().getWidth() - screenWidth);
		if(yDraw < - (ms.getbMap().getHeight() + 2*barHeight - screenHeight))
			yDraw = -(ms.getbMap().getHeight() + 2*barHeight - screenHeight);
		if(hThread != null)
			hThread.sendEmptyMessage(0);
	}
	
	//le os arquivos com os trajetos dos circulares
	public void readPath(){
		InputStream input;  
		Point p1[] = new Point[100];
		Point p2[] = new Point[100];
		Point bandex[] = new Point[5];
		try {  
            input = assetManager.open("circular1.txt"); 
            int size = input.available();  
            byte[] buffer = new byte[size];  
            input.read(buffer);  
            input.close();  
            
            String text = new String(buffer);
            StringTokenizer st = new StringTokenizer(text);
            for(int i = 0; st.hasMoreTokens(); i++){
            	float x, y;
            	x = Float.parseFloat(st.nextToken());
            	y = Float.parseFloat(st.nextToken());
            	p1[i] = new Point(x,y);
            }
        } catch (IOException e) {  
            e.printStackTrace();  
        }
		ms.setp1(p1);
		try {  
            input = assetManager.open("circular2.txt"); 
            int size = input.available();  
            byte[] buffer = new byte[size];  
            input.read(buffer);  
            input.close();  
            
            String text = new String(buffer);
            StringTokenizer st = new StringTokenizer(text);
            for(int i = 0; st.hasMoreTokens(); i++){
            	float x, y;
            	x = Float.parseFloat(st.nextToken());
            	y = Float.parseFloat(st.nextToken());
            	p2[i] = new Point(x,y);
            }
		} catch (IOException e) {  
            e.printStackTrace();  
        }
		ms.setp2(p2);    
		try {  
            input = assetManager.open("bandejao.txt"); 
            int size = input.available();  
            byte[] buffer = new byte[size];  
            input.read(buffer);  
            input.close();  
            
            String text = new String(buffer);
            StringTokenizer st = new StringTokenizer(text);
            for(int i = 0; st.hasMoreTokens(); i++){
            	float x, y;
            	x = Float.parseFloat(st.nextToken());
            	y = Float.parseFloat(st.nextToken());
            	String bandejao = st.nextToken();
            	bandex[i] = new Point(x,y,bandejao);
            }
        } catch (IOException e) {  
            e.printStackTrace();  
        }
		ms.setBandex(bandex);    
	}
	
	// ---------- action bar ---------
	// botão de menu
	private class OptionAction extends AbstractAction {
    	private Activity act;
        public OptionAction(Activity a) {
            super(R.drawable.ic_action_locate); act = a;
        }
        public void performAction(View view) {
            act.openOptionsMenu();
        }
    }
	
	// volta para a tela anterior
    private class BackAction extends AbstractAction {
    	private Activity act;
        public BackAction(Activity a) {
            super(R.drawable.ic_action_back); act = a;
        }
        public void performAction(View view) {
            act.finish();
        }
    }
    
    // volta pra home
    private class HomeAction extends AbstractAction {
    	private Activity act;
        public HomeAction(Activity a) {
            super(R.drawable.ic_launcher); act = a;
        }
        public void performAction(View view) {
        	Intent i = new Intent(act, CMEPActivity.class);
        	act.startActivity(i);
        	act.finish();
        }
    }
    
}
